<template>
	<view style="height: 100%;">
		<input v-model="TEXT" style="border: 1px solid gainsboro;" />
		<view style="width: 90%;flex-wrap:wrap">评测操作提示：{{speakMark}}</view>
		<view style="width: 90%;flex-wrap:wrap">评测中间接收结果：{{iseResult}}</view>
		<view style="width: 90%;flex-wrap:wrap">评测最终结果：{{iseFinalResult}}</view>

		<view style="position: fixed;bottom: 0;left:0;width: 100%;">
			<uni-goods-nav :fill="true" :options="[]" :buttonGroup="buttonGroup" @buttonClick="buttonClick">
			</uni-goods-nav>
		</view>
	</view>
</template>

<script>
	import * as base64 from "base-64"
	import CryptoJS from '../../static/crypto-js/crypto-js.js'
	import parser from '../../static/fast-xml-parser/src/parser'
	import * as utf8 from "utf8"

	const recorderManager = uni.getRecorderManager(); // 全局录音管理器
	export default {
		name: 'ise',
		data() {
			return {
				socketTask: {}, // 全局ws任务
				audioDataList: [], // 临时录音存储集合
				APPID: '', // 控制台获取填写
				APISecret: '',
				APIKey: '',
				ent: 'cn_vip',
				category: 'read_sentence',
				TEXT: '\uFEFF' + '今天天气怎么样',
				wsLiveFlag: false,
				iseResult: '',
				iseFinalResult: '',
				speakMark: '开始评测录音',
				buttonGroup: [{
					text: '开始评测录音',
					backgroundColor: 'green',
					color: '#fff'
				}, {
					text: '停止评测录音',
					backgroundColor: '#ffa200',
					color: '#fff'
				}],
			};
		},
		onLoad() {
			let realThis = this;
			recorderManager.onStop(function(res) {
				console.log('recorder stop' + JSON.stringify(res));
				realThis.voicePath = res.tempFilePath;
				realThis.downloadFile(res.tempFilePath);
			});
		},
		methods: {
			buttonClick(e) { // 点击评测按钮
				if (e.content.text === "开始评测录音") {
					this.speakMark = '正在评测，语音输入中...'
					const realThis = this;
					// 开始录音，初始化一些东西
					const option = {
						duration: 600000, // 录音的时长，单位 ms，最大值 600000（10 分钟）
						sampleRate: 16000, // 采样率（pc不支持）
						numberOfChannels: 1, // 录音通道数
						// encodeBitRate: 48000, // 编码码率(默认就是48000)
						frameSize: 1, // 指定帧大小，单位 KB。传入 frameSize 后，每录制指定帧大小的内容后，会回调录制的文件内容，不指定则不会回调。暂仅支持 mp3、pcm 格式。
						format: "pcm", // 音频格式，默认是 aac
					}
					recorderManager.onStart(() => {
						console.log("recorder start");
					});
					recorderManager.onFrameRecorded((res) => {
						// frameBuffer	ArrayBuffer	录音分片结果数据。  isLastFrame	Boolean	当前帧是否正常录音结束前的最后一帧
						const {
							frameBuffer
						} = res;
						// console.log(frameBuffer) 这里把音频放到临时的集合中，方便保存为文件
						if (frameBuffer) {
							realThis.audioDataList.push(frameBuffer);
							// 2、判断连接了，发送中间帧..........................................
							if (realThis.wsLiveFlag) {
								const params = {
									business: {
										cmd: "auw",
										aus: 2,
										aue: "raw"
									},
									data: {
										status: 1,
										encoding: "raw",
										data_type: 1,
										data: uni.arrayBufferToBase64(frameBuffer),
									},
								};
								console.log("发送中间帧", params, realThis.wsLiveFlag)
								realThis.socketTask.send({
									data: JSON.stringify(params),
									success() {
										console.log('中间帧发送成功')
									},
									fail(res) {
										console.log('中间帧发送失败...', res)
									}
								});
							}
						}
					});
					recorderManager.start(option); // 开始录音时，建立ws连接
					this.bulidSocketConnect();
					//setTimeout(this.bulidSocketConnect, 2000) //  main延迟2秒入口建立ws连接
				}
				if (e.content.text === "停止评测录音") {
					this.speakMark = '开始评测录音'
					// 3、发送最后一帧..........................................
					const params = {
						"business": {
							"cmd": "auw",
							"aus": 4,
							"aue": "raw"
						},
						"data": {
							"status": 2,
							"encoding": "raw",
							"data_type": 1,
							"data": "",
						}
					};
					this.socketTask.send({
						data: JSON.stringify(params),
						success(res) {
							console.log('最后一帧发送成功...', res)
						},
						fail(res) {
							console.log('最后一帧发送失败...', res)
						}
					});
					console.log("发送最后一帧", params)
					console.log('录音结束');
					recorderManager.stop();
				}
			},
			async bulidSocketConnect() {
				let myUrl = await this.getWebSocketUrl();
				// myUrl = 'wss://wdfgdzx.top/ws_server/zs'
				// console.log(encodeURI(encodeURI(myUrl).replace(/\+/g, '%2B')))
				let realThis = this;
				this.socketTask = uni.connectSocket({
					//url: encodeURI(encodeURI(myUrl).replace(/\+/g, '%2B')),
					url: myUrl,
					method: 'GET',
					success: res => {
						console.log(res, "ws成功连接...", myUrl)
						realThis.wsLiveFlag = true;
					}
				})
				realThis.socketTask.onError((res) => {
					console.log("连接发生错误", res)
				})
				realThis.socketTask.onOpen((res) => {
					console.info("wss的onOpen成功执行...", res)
					// 第一帧..........................................
					console.log('open成功...')
					let params = {
						common: {
							app_id: realThis.APPID
						},
						business: {
							category: realThis.category,
							ent: realThis.ent, // 中文
							rstcd: "utf8",
							sub: 'ise',
							tte: 'utf-8',
							cmd: "ssb",
							auf: 'audio/L16;rate=16000',
							aue: 'raw',
							text: realThis.TEXT,
						},
						data: {
							status: 0,
							data: "",
							// data: uni.arrayBufferToBase64(audioData[0]),
						},
					};
					console.log("发送第一帧...", params)
					realThis.socketTask.send({ // 发送消息，，都用uni的官方版本
						data: JSON.stringify(params),
						success() {
							console.log('第一帧发送成功')
						}
					});
				});

				// 接受到消息时
				realThis.socketTask.onMessage((res) => {
					console.log('收到API返回的内容：', res.data);
					realThis.iseResult = res.data;
					let temp = JSON.parse(res.data)
					// console.log(temp)
					if (temp.code !== 0) {
						console.log(`${temp.code}:${temp.message}`);
						realThis.socketTask.close({
							success(res) {
								console.log('关闭成功', res)
								realThis.wsLiveFlag = false;
							},
							fail(err) {
								console.log('关闭失败', err)
							}
						})
					}
					if (temp.code === 0) {
						if (res.data && temp.data.status === 2) {
							const data = base64.decode(temp.data.data);
							let decodeStr = utf8.decode(data);
							console.log(temp)
							console.log(decodeStr) // 打印完毕评测结果再关闭
							realThis.iseFinalResult = decodeStr;
							setTimeout(() => {
								realThis.socketTask.close({
									success(res) {
										console.log('关闭成功', res)
									},
									fail(err) {
										console.log('关闭失败', err)
									}
								})
							}, 2000)
						}
					}
				})

			},
			getWebSocketUrl() {
				return new Promise((resolve, reject) => {
					// 请求地址根据语种不同变化
					var url = "wss://ise-api.xfyun.cn/v2/open-ise";
					var host = "ise-api.xfyun.cn";
					var apiKeyName = "api_key";
					var date = new Date().toGMTString();
					var algorithm = "hmac-sha256";
					var headers = "host date request-line";
					var signatureOrigin = `host: ${host}\ndate: ${date}\nGET /v2/open-ise HTTP/1.1`;
					var signatureSha = CryptoJS.HmacSHA256(signatureOrigin, this.APISecret);
					var signature = CryptoJS.enc.Base64.stringify(signatureSha);
					var authorizationOrigin =
						`${apiKeyName}="${this.APIKey}", algorithm="${algorithm}", headers="${headers}", signature="${signature}"`;
					var authorization = base64.encode(authorizationOrigin);
					url = `${url}?authorization=${authorization}&date=${encodeURI(date)}&host=${host}`;

					// console.log(url)
					resolve(url); // 主要是返回地址
				});
			},
			downloadFile(url) {
				console.log(url);
				const downloadTask = uni.downloadFile({
					url: url, //文件链接
					success: res => {
						if (res.statusCode === 200) {
							uni.saveFile({
								tempFilePath: res.tempFilePath,
								success: red => {
									console.log(1, red.savedFilePath);
									uni.showToast({
										icon: 'none',
										mask: true,
										title: '文件已保存：' + red.savedFilePath, //保存路径
										duration: 3000
									});
									setTimeout(() => {
										//打开文档查看
										uni.openDocument({
											filePath: red.savedFilePath,
											success: function(res) {
												console.log('打开文件成功');
											}
										});
									}, 3000);
								}
							});
						}
					},
					fail: err => {
						uni.showToast({
							icon: 'none',
							mask: true,
							title: '失败请重新下载'
						});
					}
				});
			},
		},

		//...
	}
</script>

<style lang="scss">
	page {
		height: 100%;
	}
</style>